# 完成法相估计之后可以用于泊松表面重建

import open3d as o3d
import numpy as np

# Part1 里的点云读取
ply_point_cloud = o3d.data.PLYPointCloud()
pcd = o3d.io.read_point_cloud(ply_point_cloud.path)
print(pcd)
print(np.asarray(pcd.points))

# Part2 里的体素下采样
print("Downsample the point cloud with a voxel of 0.05")
downpcd = pcd.voxel_down_sample(voxel_size=0.05)

# 这块是新增的法向量估计
print("Recompute the normal of the downsampled point cloud")
downpcd.estimate_normals(
    search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0.5, max_nn=30))

# 表面重建
# create_from_point_cloud_poisson() 泊松重建算法接口                         那这就出来了一个问题：泊松重建是什么？（先放着不着急）
# 返回 mesh 重建后的数据集
#     densities 每个顶点的 “密度值”
mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
    downpcd,  # 输入下采样后的点云
    depth=9   # 重建细节程度（值越大细节越丰富，计算量越大）
)

# 也可以用详细日志的形式进行调用
# with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm:
#     mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(downpcd, depth=9)

# 显示
o3d.visualization.draw_geometries([mesh],
                                  zoom=0.3412,
                                  front=[0.4257, -0.2125, -0.8795],
                                  lookat=[2.6172, 2.0475, 1.532],
                                  up=[-0.0694, -0.9768, 0.2024],
                                  point_show_normal=True)

# 发现，重建出来的效果长得有点恶心
#  原因可能处在几个方面：点云质量、重建参数、后续处理

# 点云质量在预处理的时候直接解决：
#                   点云密度和法向质量
#                       体素下采样 voxel_size 太大，会丢失过多细节。如果场景有很多精细结构，把 voxel_size 改小
#                       法向估计参数，estimate_normals 中，radius 控制邻域范围，max_nn 控制邻域点数量。如果邻域范围太广（radius 大）或邻域点太少（max_nn 小），法向会不准确。

# 泊松重建，调大深度参数
# mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(
#     downpcd, 
#     depth=9  # 调大depth，提升重建分辨率
# )

# 后处理：裁剪冗余面 + 平滑网格
#        裁剪冗余几何
# mesh.remove_degenerate_triangles()
# mesh.remove_duplicated_triangles()
# mesh.remove_duplicated_vertices()
# mesh.remove_non_manifold_edges()

# # 提取最大的连通域（保留主要结构，去除小碎片）
# comp = mesh.connectivity_component_analysis()
# mesh = mesh.select_by_index(comp[0])

# 平滑网格：拉普拉斯平滑减去毛刺


